﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="YahooDataProvider.cs" company="">
//   
// </copyright>
// <summary>
//   The yahoo data provider.
// </summary>
// --------------------------------------------------------------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using System.Timers;
using Systemathics.FrameWork;
using Systemathics.FrameWork.Interfaces;
using Timer = System.Timers.Timer;

namespace Systemathics.Providers
{
    [ProviderName("Yahoo")]
    public sealed class YahooDataProvider : IDataProvider
    {
        private string PROVIDER_NAME;
        private readonly Timer SynchroneRequest;
        private readonly string url;
        private bool Disposed;
        private bool isConnected;
        private Dictionary<string, LastFeed> LastFeeds;

        private event EventHandler<TradeSeries>             _EmitTradeSeries;
        private event EventHandler<QuoteSeries>             _EmitQuoteSeries;
        private event EventHandler<BarSeries>               _EmitBarSeries;
        private event EventHandler<MarketData>              _EmitNewMarketData;
        private event EventHandler<Trade>                   _EmitNewTrade;
        private event EventHandler<Blotter>                 _EmitNewBlotter;
        private event EventHandler<FireMessageEventArgs>    _EmitError;
        private event EventHandler<FireMessageEventArgs>    _EmitConnectionStatus;

        #region constructor

        public YahooDataProvider()
        {
            PROVIDER_NAME = (Attribute.GetCustomAttribute(GetType(), typeof (ProviderName)) as ProviderName).Name;
            isConnected = false;
            url = "finance.yahoo.com";
            LastFeeds = new Dictionary<string, LastFeed>();
            SynchroneRequest = new Timer(1500);
            SynchroneRequest.Elapsed += SynchroneRequestElapsed;
            SynchroneRequest.Enabled = true;
            Thread.CurrentThread.CurrentCulture = GlobalVariables.SystemathicsCulture();
        }

        #endregion constructor

        #region IConnection Members

        string IConnection.Name
        {
            get { return PROVIDER_NAME; }
        }
        bool IConnection.isConnected
        {
            get { return isConnected; }
        }
        void IConnection.Connect()
        {
            if (!isConnected)
            {
                try
                {
                    var clnt = new TcpClient(url, 80);
                    clnt.Close();
                    isConnected = true;
                    SynchroneRequest.Start();
                    _EmitConnectionStatus(this, new FireMessageEventArgs(ConnectionStatus.Connected, Time.Now.TimeOfDay));
                }
                catch (SocketException ex)
                {
                    isConnected = false;
                    _EmitConnectionStatus(this, 
                                          new FireMessageEventArgs(ConnectionStatus.Disconnected, Time.Now.TimeOfDay));
                    _EmitError(this, new FireMessageEventArgs(ex, Time.Now.TimeOfDay));
                }
            }
        }
        void IConnection.Disconnect()
        {
            if (isConnected)
            {
                LastFeeds.Clear();
                SynchroneRequest.Stop();
            }

            isConnected = false;
            _EmitError(this, new FireMessageEventArgs("Connection to Yahoo Data Provider shutdown", Time.Now.TimeOfDay));
            _EmitConnectionStatus(this, new FireMessageEventArgs(ConnectionStatus.Disconnected, Time.Now.TimeOfDay));
        }
        void IConnection.Suscribe(Instrument instrument)
        {
            if (isConnected)
            {
                var ticker = instrument[PROVIDER_NAME];
                if (ticker != String.Empty)
                {
                    if (!LastFeeds.ContainsKey(ticker))
                    {
                        LastFeeds.Add(ticker, new LastFeed(instrument.Id));
                        _EmitError(this, new FireMessageEventArgs(ticker + " Suscribed", Time.Now.TimeOfDay));

                        string url = "http://finance.yahoo.com/d/quotes.csv?" + "s=" + ticker + "&f=sol2pl3" +
                                     ".csv";
                        var web = new WebClient();
                        string data = web.DownloadString(url);
                        string[] fields = data.Replace("\"", string.Empty).Split(',');
                        try
                        {
                            Decimal Open, High, Close, Low;
                            Decimal.TryParse(fields[1], NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat,out Open);
                            Decimal.TryParse(fields[2], NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat, out High);
                            Decimal.TryParse(fields[3], NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat, out Close);
                            Decimal.TryParse(fields[4], NumberStyles.Any, CultureInfo.InvariantCulture.NumberFormat, out Low);
                            LastFeeds[ticker].Marketdata = new MarketData(instrument.Id)
                                                               {
                                                                   Open = Open,
                                                                   High = High,
                                                                   Close = Close,
                                                                   Low = Low
                                                               };
                            LastFeeds[ticker].CheckMarketData();
                            if (LastFeeds[ticker].MarketdataCheck)
                                _EmitNewMarketData(this, LastFeeds[ticker].Marketdata);
                        }
                        catch (Exception)
                        {
                            _EmitError(this,new FireMessageEventArgs("Ticker is Not recognized", Time.Now.TimeOfDay));
                        }
                    }
                }
                else
                    _EmitError(this, new FireMessageEventArgs(ticker + " Ticker Not present in " + PROVIDER_NAME + ": No suscription", Time.Now.TimeOfDay));
            }
        }
        void IConnection.Unsubscribe(Instrument instrument)
        {
            if (isConnected)
            {
                var ticker = instrument[PROVIDER_NAME];
                if (LastFeeds.ContainsKey(ticker))
                {
                    LastFeeds.Remove(ticker);
                    _EmitError(this, new FireMessageEventArgs(ticker + " Unsuscribed", Time.Now.TimeOfDay));
                }
            }
        }

        #endregion 

        #region IDataProvider Members

        event EventHandler<FireMessageEventArgs> IConnection.EmitError
        {
            add { _EmitError += value; }
            remove { _EmitError -= value; }
        }
        event EventHandler<FireMessageEventArgs> IConnection.EmitConnectionStatus
        {
            add { _EmitConnectionStatus += value; }
            remove { _EmitConnectionStatus -= value; }
        }
        void IDataProvider.GetHistoricalData(DateTime Begin, DateTime End, Data dt, Guid id, int? BarSize)
        {
            var Ticker = GetTicker(id);
            if (Ticker != String.Empty)
            {
                switch (dt)
                {
                    case Data.Bar:
                        try
                        {
                            var barSeries = new BarSeries(id.ToString());
                            string ya = Begin.Month.ToString();
                            string yb = Begin.Day.ToString();
                            string yc = Begin.Year.ToString();
                            string yd = End.Month.ToString();
                            string ye = End.Day.ToString();
                            string yf = End.Year.ToString();
                            string url = "http://ichart.finance.yahoo.com/table.csv?s=" + Ticker + "&a=" + ya +
                                         "&b=" + yb + "&c=" + yc + "&d=" + yd + "&e=" + ye + "&f=" + yf + "&g=d" +
                                         ".csv";
                            var DailyRequest = new WebClient();
                            string[] Reply = DailyRequest.DownloadString(new Uri(url)).Split(new[] {'\n'});
                            barSeries.BarType = BarType.Seconds;
                            barSeries.BarSize = BarSize;
                            for (int j = Reply.Length - 2; j >= 1; j--)
                            {
                                var b = new Bar();
                                b.Id = id;
                                string str = Reply[j];
                                string[] asie = str.Split(',');
                                if (asie.Length < 7)
                                    break;
                                b.BeginTime = DateTime.ParseExact(asie[0], "yyyy-MM-dd", null);
                                b.EndTime = DateTime.ParseExact(asie[0], "yyyy-MM-dd", null);
                                b.Open = Decimal.Parse(asie[1]);
                                b.High = Decimal.Parse(asie[2]);
                                b.Low = Decimal.Parse(asie[3]);
                                b.Close = Decimal.Parse(asie[4]);
                                b.Size = 86400;
                                b.Volume = long.Parse(asie[5]);
                                barSeries.Add(b);
                            }

                            _EmitBarSeries(this, barSeries);
                        }
                        catch (Exception ex)
                        {
                            _EmitError(this, new FireMessageEventArgs(ex, Time.Now.TimeOfDay));
                        }

                        ;
                        break;
                    case Data.Quote:
                        _EmitError(this, new FireMessageEventArgs("No Historical Quotes Support from Yahoo", Time.Now.TimeOfDay));
                        break;
                    case Data.Trade:
                        _EmitError(this, new FireMessageEventArgs("No Historical trades support from Yahoo",  Time.Now.TimeOfDay));
                        break;
                    default:
                        break;
                }
            }
        }
        void IDataProvider.UpdateInstruments()
        {
            using (var db = new SystemathicsEntities(GlobalVariables.EntitiesConnectionString()))
            {
                IQueryable<DBTickers> var = db.DBTickers.Select(u => u);
                foreach (DBTickers t in var)
                {
                    if (t.Provider == PROVIDER_NAME)
                    {
                        string url = "http://finance.yahoo.com/d/quotes.csv?" + "s=" + t.Ticker + "&f=qdj1" + ".csv";
                        var web = new WebClient();
                        web.DownloadStringCompleted += WebDownloadCompletedUpdateInstruments;
                        web.DownloadStringAsync(new Uri(url));
                    }
                }
            }
        }
        event EventHandler<MarketData> IDataProvider.EmitNewMarketData
        {
            add { _EmitNewMarketData += value; }
            remove { _EmitNewMarketData -= value; }
        }
        event EventHandler<Trade> IDataProvider.EmitNewTrade
        {
            add { _EmitNewTrade += value; }
            remove { _EmitNewTrade -= value; }
        }
        event EventHandler<Blotter> IDataProvider.EmitNewBlotter
        {
            add { _EmitNewBlotter += value; }
            remove { _EmitNewBlotter -= value; }
        }
        event EventHandler<BarSeries> IDataProvider.EmitBarSeries
        {
            add { _EmitBarSeries += value; }
            remove { _EmitBarSeries -= value; }
        }
        event EventHandler<TradeSeries> IDataProvider.EmitTradeSeries
        {
            add { _EmitTradeSeries += value; }
            remove { _EmitTradeSeries -= value; }
        }
        event EventHandler<QuoteSeries> IDataProvider.EmitQuoteSeries
        {
            add { _EmitQuoteSeries += value; }
            remove { _EmitQuoteSeries -= value; }
        }

        void IDataProvider.UpdateCurrencies()
        {
        }

        #endregion

        #region private methods

        private String GetTicker(Guid guid)
        {
            using (var db = new SystemathicsEntities(GlobalVariables.EntitiesConnectionString()))
                return db.DBTickers.Where(u => u.DBInstruments.ID == guid && u.Provider == PROVIDER_NAME).FirstOrDefault().Ticker;
        }

        private void SynchroneRequestElapsed(object sender, ElapsedEventArgs e)
        {
            foreach (string ticker in LastFeeds.Keys)
            {
                try
                {
                    // Symbol - TradeTime - LastTrade - LastSize - Open - High - Low - Close
                    string url = "http://finance.yahoo.com/d/quotes.csv?" + "s=" + ticker + "&f=st1l1k3" + ".csv";
                    var web = new WebClient();
                    web.DownloadStringCompleted += WebDownloadCompletedRealtime;
                    web.DownloadStringAsync(new Uri(url));
                }
                catch (Exception ex)
                {
                    _EmitError(this, new FireMessageEventArgs(ex, Time.Now.TimeOfDay));
                }

                ;
            }
        }
        private void WebDownloadCompletedRealtime(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                // Symbol - TradeTime - LastTrade - LastSize - Open - High - Low - Close
                string[] fields = e.Result.Replace("N/A", "0").Replace("\"", string.Empty).Split(',');

                DateTime TradeTime;
                Decimal LastTrade;
                int TradeSize;
                string Ticker_Reply;

                Ticker_Reply = fields[0];
                TradeTime = DateTime.Parse(fields[1], CultureInfo.InvariantCulture.DateTimeFormat);
                LastTrade = Decimal.Parse(fields[2], CultureInfo.InvariantCulture.NumberFormat);
                TradeSize = int.Parse(fields[3], CultureInfo.InvariantCulture.NumberFormat);

                LastFeeds[Ticker_Reply].Trade.Price = LastTrade;
                LastFeeds[Ticker_Reply].Trade.Size = TradeSize;
                LastFeeds[Ticker_Reply].Trade.Time = Time.Now;
                LastFeeds[Ticker_Reply].Trade.TickInfo = TickInfo.LastTrade | TickInfo.LastSize;

                if (LastFeeds[Ticker_Reply].TradeCheck)
                    _EmitNewTrade(this, LastFeeds[Ticker_Reply].Trade);
                else
                    LastFeeds[Ticker_Reply].CheckTrade();
            }
            catch (Exception ex)
            {
                _EmitError(this, new FireMessageEventArgs(ex, Time.Now.TimeOfDay));
            }
        }
        private void WebDownloadCompletedUpdateInstruments(object sender, DownloadStringCompletedEventArgs e)
        {
            try
            {
                string[] fields = e.Result.Replace("N/A", "0").Replace("\"", string.Empty).Split(',');
                string[] temp = fields[0].Split(' ');

                // DateTime ExDividendDate = new DateTime(DateTime.Now.Year, temp[0], temp[1]);
                string OstEvent = "Dividend";
                double OstValue = Double.Parse(fields[1]);
                long Capitalization = long.Parse(fields[2]);
            }
            catch (Exception ex)
            {
                _EmitError(this, new FireMessageEventArgs(ex, Time.Now.TimeOfDay));
            }
        }

        #endregion private methods

        private void Dispose(bool disposing)
        {
            if (!Disposed)
            {
                if (disposing)
                {
                    GC.SuppressFinalize(this);
                    LastFeeds = null;
                }

                Disposed = true;
            }
        }
        void IDisposable.Dispose()
        {
            SynchroneRequest.Dispose();
            Dispose(true);
        }
    }
}

/*
      Symbol                            s
      Name                              n
      Last Trade (With Time)            l
      Last Trade (Price Only)           l1
      Last Trade Date                   d1
      Last Trade Time                   t1
      Last Trade Size                   k3
      Change and Percent Change         c
      Change                            c1
      Change in Percent                 p2
      Ticker Trend                      t7
      Volume                            v
      Average Daily Volume              a2
      More Info                         i
      Trade Links                       t6
      Bid                               b
      Bid Size                          b6
      Ask                               a
      Ask Size                          a5
      Previous Close                    p
      Open                              o
      Day's Range                       m
      52-week Range                     w
      Change From 52-wk Low             j5
      Pct Chg From 52-wk Low            j6
      Change From 52-wk High            k4
      Pct Chg From 52-wk High           k5
      Earnings/Share                    e
      P/E Ratio                         r
      Short Ratio                       s7
      Dividend Pay Date                 r1
      Ex-Dividend Date                  q
      Dividend/Share                    d
      Dividend Yield                    y
      Float Shares                      f6
      Market Capitalization             j1
      1yr Target Price                  t8
      EPS Est. Current Yr               e7
      EPS Est. Next Year                e8
      EPS Est. Next Quarter             e9
      Price/EPS Est. Current Yr         r6
      Price/EPS Est. Next Yr            r7
      PEG Ratio                         r5
      Book Value                        b4
      Price/Book                        p6
      Price/Sales                       p5
      EBITDA                            j4
      50-day Moving Avg                 m3
      Change From 50-day Moving Avg     m7
      Pct Chg From 50-day Moving Avg    m8
      200-day Moving Avg                m4
      Change From 200-day Moving Avg    m5
      Pct Chg From 200-day Moving Avg   m6
      Shares Owned                      s1
      Price Paid                        p1
      Commission                        c3
      Holdings Value                    v1
      Day's Value Change                w1,
      Holdings Gain Percent             g1
      Holdings Gain                     g4
      Trade Date                        d2
      Annualized Gain                   g3
      High Limit                        l2
      Low Limit                         l3
      Notes                             n4
      Last Trade (Real-time) with Time  k1
      Bid (Real-time)                   b3
      Ask (Real-time)                   b2
      Change Percent (Real-time)        k2
      Change (Real-time)                c6
      Holdings Value (Real-time)        v7
      Day's Value Change (Real-time)    w4
      Holdings Gain Pct (Real-time)     g5
      Holdings Gain (Real-time)         g6
      Day's Range (Real-time)           m2
      Market Cap (Real-time)            j3
      P/E (Real-time)                   r2
      After Hours Change (Real-time)    c8
      Order Book (Real-time)            i5
      Stock Exchange                    x

*/